package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.cart.service.CartInfoSyncService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author 李旭
 * @date 2022/1/17 14:35
 * @Description:
 */
@Service
public class CartInfoServiceImpl implements CartInfoService {


    @Autowired
    private RedisTemplate redisTemplate;//Hash类型
    @Autowired
    private ProductFeignClient productFeignClient;
    //Spring注解式

    @Autowired
    private CartInfoSyncService cartInfoSyncService;

    //加入购物车
    @Override
    public void addCart(Long skuId, Integer skuNum, String userId) {//3
        //1:查询购物车数据
        String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                RedisConst.USER_CART_KEY_SUFFIX;
        /**
         *  CartInfo 对象
         *
         *  Map  userId = new HashMap();
         *  userId.put(id,CartInfo)
         * userId.put(id,CartInfo)
         */
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartInfoCacheKey, String.valueOf(skuId));
        //判断当前商品是否已经在购物车存在
        if(null != cartInfo){
            //存在了 追加数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            cartInfo.setIsChecked(1);

            System.out.println("updateSync当前加入购物车的主线程：" + Thread.currentThread().getName());
            //异步更新DB
            cartInfoSyncService.updateSync(cartInfo);
        }else{
            // 不存在  添加商品
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            System.out.println("insertSync当前加入购物车的主线程：" + Thread.currentThread().getName());
            //异步添加DB
            cartInfoSyncService.insertSync(cartInfo);
        }
        //保存到缓存中
        redisTemplate.opsForHash().put(cartInfoCacheKey,skuId.toString(),cartInfo);
    }
    //加入购物车 查询
    @Override
    public CartInfo toCart(Long sId, Integer sNum, String userId) {
        //1:查询购物车数据
        String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                RedisConst.USER_CART_KEY_SUFFIX;
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().
                get(cartInfoCacheKey, String.valueOf(sId));
        cartInfo.setSkuNum(sNum);
        return cartInfo;
    }


    //去购物车结算  查询购物车集合
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //1:判断真实用户ID是存在 （判断是否登录了）
        if(!StringUtils.isEmpty(userId)){
            //有真实用户的ID
            //1.1:判断是否有临时用户的ID
            if(!StringUtils.isEmpty(userTempId)){
                //有临时用户的ID
                return mergeCartInfoList(userId,userTempId);
            }else{
                //没有临时用户的ID  直接返回真实用户ID对应的购物车集合
                return getCartInfoList(userId);
            }
        }else{
            //没有真实用户的Id
            //2:判断是否有临时用户的ID
            if(!StringUtils.isEmpty(userTempId)){
                //有临时用户的ID   查临时用户的ID对应的购物车集合
                return getCartInfoList(userTempId);
            }else{
                //啥也没有
                return null;
            }
        }

    }


    //选中或取消
    @Override
    public void checkCart(Long skuId, Integer isChecked) {

        //任意地方取值
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(null != requestAttributes){
            HttpServletRequest request = requestAttributes.getRequest();
            String userId = AuthContextHolder.getUserId(request);
            if(StringUtils.isEmpty(userId)){
                userId = AuthContextHolder.getUserTempId(request);
            }
            //1:先改  Redis
            String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                    RedisConst.USER_CART_KEY_SUFFIX;
            CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().
                    get(cartInfoCacheKey, String.valueOf(skuId));
            //选中或取消
            cartInfo.setIsChecked(isChecked);
            redisTemplate.opsForHash().put(cartInfoCacheKey,String.valueOf(skuId),cartInfo);
            //2:DB
            cartInfoSyncService.updateSync(cartInfo);
        }

    }
    //查询选中的购物车
    @Override
    public List<CartInfo> findCartInfoListAndChecked(String userId) {
        return getCartInfoListAndChecked(userId);
    }
    //查询购物车集合 选中的购物车
    private List<CartInfo> getCartInfoListAndChecked(String userId){
        String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartInfoCacheKey);
        if(CollectionUtils.isEmpty(cartInfoList)){
            return null;
        }
        //查询实时价格
        return cartInfoList.stream().peek(cartInfo -> {
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }).filter(cartInfo -> 1 == cartInfo.getIsChecked()).collect(Collectors.toList());
    }

    //合并购物车集合  代码巅峰
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //真实用户的购物车集合
        List<CartInfo> cartInfoListByUserId = getCartInfoList(userId);
        List<CartInfo> cartInfoListByUserTempId = getCartInfoList(userTempId);
        //判断
        if(!CollectionUtils.isEmpty(cartInfoListByUserId)){
            if(!CollectionUtils.isEmpty(cartInfoListByUserTempId)){
                //合并
                Map<Long, CartInfo> mapByUserId = cartInfoListByUserId.stream().collect(
                        Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
                String cartInfoCacheKeyByUserTempId = RedisConst.USER_KEY_PREFIX + userTempId +
                        RedisConst.USER_CART_KEY_SUFFIX;
                String cartInfoCacheKeyByUserId = RedisConst.USER_KEY_PREFIX + userId +
                        RedisConst.USER_CART_KEY_SUFFIX;
                //注意事项： 遇到相同的商品追加数量  遇到不同的商品添加新商品
                for (CartInfo cartInfoByUserTempId : cartInfoListByUserTempId) {
                    //判断是否有相同的商品
                    CartInfo cartInfoByUserId = mapByUserId.get(cartInfoByUserTempId.getSkuId());
                    if(null != cartInfoByUserId){
                        //存在
                        cartInfoByUserId.setSkuNum(//追加数量
                                cartInfoByUserId.getSkuNum() + cartInfoByUserTempId.getSkuNum());
                        cartInfoByUserId.setIsChecked(1);
                        //---持久化：DB
                        //更新DB
                        cartInfoSyncService.updateSync(cartInfoByUserId);
                        //删除DB
                        cartInfoSyncService.deleteSync(cartInfoByUserTempId);
                        //---持久化：Redis
                        //删除Redis
                        redisTemplate.opsForHash().delete(cartInfoCacheKeyByUserTempId,
                                cartInfoByUserTempId.getSkuId().toString());
                        //添加
                        redisTemplate.opsForHash().put(cartInfoCacheKeyByUserId,
                                cartInfoByUserId.getSkuId().toString(),cartInfoByUserId);

                    }else{
                        //不存在 作为新商品添加进来
                        mapByUserId.put(cartInfoByUserTempId.getSkuId(),cartInfoByUserTempId);
                        //---持久化：
                        //更新DB
                        cartInfoSyncService.updateSync(userId,userTempId,cartInfoByUserTempId.getSkuId());
                        // Redis
                        //删除Redis
                        redisTemplate.opsForHash().delete(cartInfoCacheKeyByUserTempId,
                                cartInfoByUserTempId.getSkuId().toString());
                        //添加Redis
                        cartInfoByUserTempId.setUserId(userId);//更新成真实用户的ID
                        redisTemplate.opsForHash().put(cartInfoCacheKeyByUserId,
                                cartInfoByUserTempId.getSkuId().toString(),cartInfoByUserTempId);
                    }
                }
                //   父 强转成儿子 （儿子必须是活点）
                return new ArrayList<>(mapByUserId.values());
            }else{
                ////真实用户的购物车集合是有的  临时没有
                return cartInfoListByUserId;
            }
        }else{
            //真实用户的购物车集合 没有
            //---持久化  DB Redis
            //异步持久化DB
            cartInfoSyncService.updateSyncBatch(userId,userTempId);
            //持久化 Redis
            //1:删除
            deleteRedisData(userTempId);
            //2:添加
            Map<String, CartInfo> mapByUserTempId = cartInfoListByUserTempId.stream()
                    .peek(cartInfo -> {
                        cartInfo.setUserId(userId);
                    }).collect(
                    Collectors.toMap(cartInfo -> cartInfo.getSkuId().toString(),
                            cartInfo -> cartInfo));
            addRedisDataBatch(mapByUserTempId,userId);
            return cartInfoListByUserTempId;
        }
    }

    //持久 化Redis删除
    private void deleteRedisData(String userId){
        String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.delete(cartInfoCacheKey);
    }
    //持久 化Redis批量添加
    private void addRedisDataBatch(Map<String, CartInfo> mapByUserTempId,String userId){
        String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.opsForHash().putAll(cartInfoCacheKey,mapByUserTempId);
    }
    //查询购物车集合
    private List<CartInfo> getCartInfoList(String userId){
        String cartInfoCacheKey = RedisConst.USER_KEY_PREFIX + userId +
                RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartInfoCacheKey);
        if(CollectionUtils.isEmpty(cartInfoList)){
            return null;
        }
        //1:查询实时价格
        //2:可能需要排序
        return cartInfoList.stream().peek(cartInfo -> {
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }).sorted((cartInfo1, cartInfo2) -> cartInfo1.getSkuNum() - cartInfo2.getSkuNum()
        ).collect(Collectors.toList());
    }
}
